package com.example.demo.service;

import com.alibaba.druid.util.StringUtils;
import com.example.demo.bean.Goods;
import com.example.demo.bean.GoodsSeckill;
import com.example.demo.bean.Order;
import com.example.demo.bean.User;
import com.example.demo.dao.GoodsDao;
import com.example.demo.dao.OrderDao;
import com.example.demo.exception.CodeMsg;
import com.example.demo.exception.GlobalException;
import com.example.demo.redis.BaseRedisImpl;
import com.example.demo.redis.RedisServer;
import com.example.demo.redisPrefix.GoodsPrefixAndExpireSecond;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.sun.org.apache.bcel.internal.classfile.Code;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ResponseBody;
import org.thymeleaf.spring4.context.SpringWebContext;
import org.thymeleaf.spring4.view.ThymeleafViewResolver;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Locale;
import java.util.Map;

@Service
public class GoodsService {
    private final Integer Conflict_Count=5;//乐观锁冲突次数


    @Autowired
    RedisServer redisServer;


    @Autowired
    ApplicationContext applicationContext;

    @Autowired
    ThymeleafViewResolver thymeleafViewResolver;


    @Autowired
    private OrderService orderService;

    @Autowired
    private GoodsService goodsService;

    @Autowired
     OrderDao orderDao;

    @Autowired
    GoodsDao goodsDao;



    public GoodsSeckill findGoods(Long goodsId){
        return goodsDao.findGoodsSeckillAllInfro(goodsId);
    }

    //返回的是goodList的json页面
    public String goodsService(User user, Model model, HttpServletRequest request, HttpServletResponse response){
        //从redis中查找缓存页面，（有问题）
        String htmlStr=null;
        try {
            htmlStr = redisServer.get(GoodsPrefixAndExpireSecond.goodsStorage, "", String.class);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        //既不是null也不是length=0
        if (!StringUtils.isEmpty(htmlStr)){
            return htmlStr;
        }

        //否则就先去数据库中查找
        List<GoodsSeckill> goodsSeckillList = goodsDao.findGoodsSeckill();
        if (goodsSeckillList==null||goodsSeckillList.size()==0){
            throw  new GlobalException(CodeMsg.SERVER_ERROR);
        }

        //将user和goodsSeckillList存入request域中，因为goodsList页面会用到
        model.addAttribute("user",user);
        model.addAttribute("goodsList",goodsSeckillList);
        //进行good_list.html页面缓存
        Map<String, Object> map = model.asMap();
        Locale locale = request.getLocale();
        SpringWebContext context=new SpringWebContext(request,response,request.getServletContext(),locale,map,applicationContext);
        htmlStr = thymeleafViewResolver.getTemplateEngine().process("goods_List", context);
        System.out.println(htmlStr);

        //然后将页面缓存存入redis
        if (htmlStr!=null){
            try {
                String set = redisServer.set(GoodsPrefixAndExpireSecond.goodsStorage, "", htmlStr);
                System.out.println(set);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }else {
            throw new GlobalException(CodeMsg.SERVER_ERROR);
        }

        return htmlStr;


    }


    @Transactional
    public Integer goodsSeckill(User user,GoodsSeckill goodsSeckill){
        Long goodsId = goodsSeckill.getId();


        //先秒杀商品库存减一
        Integer flag = goodsService.reduceStockCount(goodsSeckill);
        Integer orderInsertFlag=0;
        if (flag==1){
            //存入订单详情表和订单秒杀表
            orderInsertFlag = orderService.insertOrderInfro(user, goodsSeckill);
        }else {
            //此时秒杀库存商品减一失败，那只有一个原因，那就是就是商品被秒杀完了，及时自己抢到了令牌也没用(网速太慢）
            try {
                redisServer.set(GoodsPrefixAndExpireSecond.goodsOver,""+goodsId,true);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
                throw new GlobalException(CodeMsg.SERVER_ERROR);
            }
        }
        return orderInsertFlag;
    }


    @Transactional
    public Integer reduceStockCount(GoodsSeckill goodsSeckill){
        //这里使用到乐观锁来防止并发造成的错误,使用版本号来进行控制
        Long goodsId = goodsSeckill.getId();
        Integer number=0;
        GoodsSeckill goodsSeckillNow=new GoodsSeckill();
        goodsSeckillNow.setId(goodsId);

        //是否成功标识
        Integer flag=0;
        do{
            //获得当前数据库的秒杀商品的操作版本号
            Integer version = goodsDao.findVersion(goodsId);
            goodsSeckillNow.setVersion(version);
            //在进行减一操作，通过与当前版本号进行对照
            flag = goodsDao.updateStockCount(goodsSeckillNow);
            if (flag==1){
                break;
            }
        }while (number<Conflict_Count);
        return flag;
    }
}
